package com.lzh.file.controller;

import com.google.common.collect.Lists;
import com.lzh.file.constant.FileConstant;
import com.lzh.file.entity.FileInfo;
import com.lzh.file.redis.RedisOperator;
import com.lzh.file.service.IFileService;
import com.lzh.runke.core.web_base.Result;
import com.lzh.runke.core.web_base.helper.UUIDHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/file")
public class FileController {

    @Resource
    private IFileService fileService;

    @Resource
    private RedisOperator redisOperator;

    private String username = "Test";
    private boolean securityEnabled = false;
//    @Lazy
//    @Resource
//    private UserSecurityService<UserBase> userSecurityService;

//    @Autowired(required = false)
//    private SecurityCoreConfigProperties config;

    /**
     * 普通文件令牌生成(等保三)
     *
     * @param fileInfo
     * @return
     */
    @RequestMapping("/getDownloadKey")
    public Result<String> initDownloadKey(@RequestBody FileInfo fileInfo, HttpServletRequest request) {
        // 生成一次性令牌
        String key = UUIDHelper.randomUUID();

//        String username = userSecurityService.getCurrentUsername();
//        Boolean securityEnabled = config.getEnabled();
        if (!securityEnabled) {
            log.info("未集成登录，文件下载跳过校验");
            // 将相关信息存储至redis，超时时间为5分钟
            redisOperator.set(FileConstant.FILE_PRE + key, fileInfo, 300, TimeUnit.SECONDS);
            return Result.<String>builder().success(true).data(key).build();
        }

        if (StringUtils.isBlank(username)) {
            return Result.<String>builder().success(false).message("获取当前登录用户信息失败").build();
        }

        // 将用户信息与文件信息绑定
        fileInfo.setUsername(username);

        // 将相关信息存储至redis，超时时间为5分钟
        redisOperator.set(FileConstant.FILE_PRE + key, fileInfo, 300, TimeUnit.SECONDS);
        return Result.<String>builder().success(true).data(key).build();
    }

    /**
     * 下载普通文件(等保三)
     *
     * @param key
     * @return
     */
    @RequestMapping(value = "/download/{key}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public ResponseEntity<byte[]> download(@PathVariable("key") String key, HttpServletRequest request) {
//        String username = userSecurityService.getCurrentUsername();
//        Boolean securityEnabled = config.getEnabled();

        // 从redis中获取文件相关信息
        FileInfo fileInfo = redisOperator.get(FileConstant.FILE_PRE + key, FileInfo.class);

        if (!securityEnabled) {
            log.info("未集成登录，文件下载跳过校验");
            ResponseEntity<byte[]> responseEntity = buildDownloadResponse(fileInfo);
            redisOperator.delete(FileConstant.FILE_PRE + key);
            return responseEntity;
        }

        if (StringUtils.isBlank(username)) {
            log.info("获取当前用户信息失败");
            return null;
        }

        // 鉴权：校验当前用户是否匹配
        if (!username.equals(fileInfo.getUsername())) {
            log.info("key校验失败，不允许下载该文件");
            return null;
        }
        ResponseEntity<byte[]> responseEntity = buildDownloadResponse(fileInfo);
        redisOperator.delete(FileConstant.FILE_PRE + key);
        return responseEntity;
    }


    /**
     * 文件下载（非等保要求）
     *
     * @param filename
     * @param originalName
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/download/{filename:.+}/{originalName:.+}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public ResponseEntity<byte[]> download(@PathVariable("filename") String filename,
                                           @PathVariable("originalName") String originalName) {
        FileInfo fileInfo = FileInfo.builder().filename(filename).originalName(originalName).build();
        return buildDownloadResponse(fileInfo);
    }

    private ResponseEntity<byte[]> buildDownloadResponse(FileInfo fileInfo) {

        byte[] file = fileService.download(fileInfo.getFilename());

        HttpHeaders headers = new HttpHeaders();
        String fileName = null;
        try {
            if (StringUtils.isNotBlank(fileInfo.getOriginalName())) {
                fileName = URLEncoder.encode(fileInfo.getOriginalName(), StandardCharsets.UTF_8.name());
            } else {
                fileName = URLEncoder.encode(fileInfo.getFilename(), StandardCharsets.UTF_8.name());
            }
        } catch (UnsupportedEncodingException e) {
            log.error("下载普通文件：编码异常");
            log.error(e.getMessage());
        }
        headers.setContentDispositionFormData("attachment", fileName);
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        List<String> accessControlExposeHeaders = Lists.newArrayListWithExpectedSize(1);
        String accessControlExposeHeader = "Content-Disposition";
        accessControlExposeHeaders.add(accessControlExposeHeader);
        headers.setAccessControlExposeHeaders(accessControlExposeHeaders);
        return new ResponseEntity<>(file, headers, HttpStatus.CREATED);
    }

    /**
     * 文件/图片预览
     *
     * @param filename
     * @param response
     */
    @RequestMapping(value = "/preview/{filename:.+}", produces = {MediaType.IMAGE_PNG_VALUE, MediaType.IMAGE_JPEG_VALUE})
    public void preview(@PathVariable("filename") String filename, HttpServletResponse response) {
        response.setHeader("Content-Type", MediaType.IMAGE_PNG_VALUE + ";" + MediaType.IMAGE_JPEG_VALUE);

        Result<byte[]> result = fileService.preview(filename);
        try {
            OutputStream os = response.getOutputStream();
            os.write(result.getData());
            os.flush();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 上传文件
     *
     * @param file
     * @return
     */
    @RequestMapping("/upload")
    public Result<FileInfo> upload(MultipartFile file) {
        return fileService.upload(file);
    }
}
